/*
 * Copyright (C) 2010 M. Hautle.
 * 
 * This file is part of TrackedBean.
 * 
 * TrackedBean is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free
 * Software Foundation, either version 3 of the License, or (at your option) any later version.
 * 
 * TrackedBean is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
 * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
 * 
 * You should have received a copy of the GNU Lesser General Public License along with TrackedBean. If not, see <http://www.gnu.org/licenses/>.
 */
package ch.trackedbean.binding.action;

/**
 * Path to a group inside a menu.<br>
 * Consider to use the {@link MenuPathBuilder} instead of calling the constructor directly.
 * 
 * @author M. Hautle
 */
public class MenuPath {
    /** The internal path representation. */
    private final MenuPathSegment[] path;

    /** The last group in the path or null for the default group. */
    private final String lastGroup;

    /** The order value of {@link #lastGroup}. */
    private final int lastGroupOrder;

    /**
     * Default constructor.
     * 
     * @param path The path to the last submenu
     * @param group The last group or null for the default group
     * @param groupOrder The order value of the last group
     * @throws IllegalArgumentException If the given path is invalid
     */
    public MenuPath(MenuPathSegment[] path, String group, int groupOrder) {
        validate(path);
        this.path = path;
        this.lastGroup = group;
        this.lastGroupOrder = groupOrder;
    }

    /**
     * Returns the path towards the desired submenu.
     * 
     * @return Returns the path.
     */
    public MenuPathSegment[] getPath() {
        return path;
    }

    /**
     * The destination group. This is the group to use in the submenu described by {@link #getPath()}.
     * 
     * @return The group or null for the default group
     */
    public String getLastGroup() {
        return lastGroup;
    }

    /**
     * The order value of {@link #getLastGroup()}
     * 
     * @return The order value
     */
    public int getLastGroupOrder() {
        return lastGroupOrder;
    }

    /**
     * Checks the given path on it's validity.
     * 
     * @param path The path
     * @throws IllegalArgumentException If the path is illegal
     */
    private static void validate(MenuPathSegment[] path) throws IllegalArgumentException {
        for (int i = 0; i < path.length; i++)
            if (path[i].getSubMenu() == null)
                throw new IllegalArgumentException("The segment " + i + " of the path must contain a submenu entry this is required by it's successor!");
    }

    /**
     * Compares two group descriptions against each other.
     * 
     * @param g1 The first group or null
     * @param o1 The group order of the first group
     * @param g2 The second group or null
     * @param o2 The group order of the second group
     * @return @return 0,1,-1 if the first group is equals, 'bigger' or 'lower' than the second group
     */
    public static int compareGroups(String g1, int o1, String g2, int o2) {
        // same - both in the default/same group
        if (g1 == g2)
            return 0;
        // first is in the default group - check only if the second group has a higher order value
        if (g1 == null)
            return o2 > o1 ? -1 : 1;
        // second is in the default group - check only if the first group has a higher order value
        if (g2 == null)
            return o1 > o2 ? 1 : -1;
        // check group
        final int grp = g1.compareTo(g2);
        // same group
        if (grp == 0)
            return 0;
        // check group order
        if (o1 < o2)
            return -1;
        if (o1 > o2)
            return 1;
        // same group order - text difference matters
        return grp;
    }

    /**
     * Immutable representation of a menu path segment.
     * 
     * @author M. Hautle
     */
    public static class MenuPathSegment {
        /** The name of the next sub menu. */
        private final String subMenu;

        /** The order value of the {@link #subMenu}. */
        private final int subMenuOrder;

        /** The name of the group to which this entry belongs or null for the default group. */
        private final String group;

        /** The oder value of {@link #group}. */
        private final int groupOrder;

        /**
         * Default constructor.
         * 
         * @param group The name of the group to which this entry belongs or null
         * @param groupOrder The order value of the group
         * @param subMenu The name of the next sub menu or null
         * @param subMenuOrder The order value of the sub menu
         */
        public MenuPathSegment(String group, int groupOrder, String subMenu, int subMenuOrder) {
            this.subMenu = subMenu;
            this.subMenuOrder = subMenuOrder;
            this.group = group;
            this.groupOrder = groupOrder;
        }

        /**
         * Returns the name of the next sub menu.
         * 
         * @return The next sub menus name or null if there is no sub menu
         */
        public String getSubMenu() {
            return subMenu;
        }

        /**
         * Returns the order value of {@link #getSubMenu()}.
         * 
         * @return The order value
         */
        public int getSubMenuOrder() {
            return subMenuOrder;
        }

        /**
         * Return the name of the group to which this entry belongs.
         * 
         * @return The group name or null for the default group
         */
        public String getGroup() {
            return group;
        }

        /**
         * Returns the order value of {@link #getGroup()}.
         * 
         * @return The order value
         */
        public int getGroupOrder() {
            return groupOrder;
        }

        /**
         * Compares the {@link #getGroup()} and {@link #getGroupOrder()} information against each other.
         * 
         * @param other The other segment
         * @return 0,1,-1 if this segments group is equals, 'bigger' or 'lower' than the group of the other segment
         */
        public int compareGroups(MenuPathSegment other) {
            return MenuPath.compareGroups(group, groupOrder, other.group, other.groupOrder);
        }
    }
}
